from django.db import transaction
from rest_framework import serializers

from apps.goods.models import SKU, SKUSpecification, SPUSpecification, SpecificationOption


class SKUSpecificationSerializer(serializers.ModelSerializer):
    """
        sku具体规格表序列化器
    """
    spec_id = serializers.IntegerField()
    option_id = serializers.IntegerField()

    class Meta:
        model = SKUSpecification
        fields = ('spec_id', 'option_id')


class SKUSerialzier(serializers.ModelSerializer):
    """
     {
                "spu": "商品SPU名称",
                "spu_id": "商品SPU ID",
                "category_id": "三级分类id",
                "category": "三级分类名称",
                "specs": [
                    {
                        "spec_id": "规格id",
                        "option_id": "选项id"
                    },
                    ...
                ]
            },
    """
    # 关联返回  副表关联主表返回  sku是副表  spu是主表 caption是主表
    spu = serializers.StringRelatedField(read_only=True)
    spu_id = serializers.IntegerField()
    category = serializers.StringRelatedField(read_only=True)
    category_id = serializers.IntegerField()

    # 关联返回  主表嵌套副表返回  sku是主表 单独定义规格序列化器指定两个字段返回
    specs = SKUSpecificationSerializer(many=True)

    class Meta:
        model = SKU
        fields = '__all__'

    # @transaction.atomic()
    def create(self, validated_data):
        """
            保存sku表和sku具体规格表数据
        """
        # 当要进行数据操作时，开启事务
        with transaction.atomic():
            # 事务使用 1、设置保存点，在出现错误时回滚到保存点
            save_point = transaction.savepoint()
            try:
                # pop从字典中获取值后将原来字段删除
                specs = validated_data.pop('specs')
                # 保存sku表数据
                sku = SKU.objects.create(**validated_data)
                # 保存sku具体规格表
                for data in specs:
                    SKUSpecification.objects.create(sku=sku, spec_id=data['spec_id'], option_id=data['option_id'])
            except:
                # 捕获到异常，说明有代码出现问题需要回滚到保存点
                transaction.savepoint_rollback(save_point)
            # 没有捕获到异常 提交
            transaction.savepoint_commit(save_point)
        return sku

    def update(self, instance, validated_data):
        """
            instance: 要修改的数据对象
            validated_data：验证后的数据内容
        """
        # 当要进行数据操作时，开启事务
        with transaction.atomic():
            # 事务使用 1、设置保存点，在出现错误时回滚到保存点
            save_point = transaction.savepoint()
            try:
                # pop从字典中获取值后将原来字段删除
                specs = validated_data.pop('specs')
                # 修改sku表数据
                SKU.objects.filter(id=instance.id).update(**validated_data)
                # 查询修改后的数据对象
                sku = SKU.objects.get(id=instance.id)
                # 修改sku具体规格表
                for data in specs:
                    # 实际是修改商品的选项
                    SKUSpecification.objects.filter(sku=sku,spec_id=data['spec_id']).update(option_id=data['option_id'])
            except:
                # 捕获到异常，说明有代码出现问题需要回滚到保存点
                transaction.savepoint_rollback(save_point)
            # 没有捕获到异常 提交
            transaction.savepoint_commit(save_point)
        return sku


class SpecificationOptionSerialzier(serializers.ModelSerializer):
    """
        选项表序列化器
    """

    class Meta:
        model = SpecificationOption
        fields = ('id', 'value')


class SPUSpecificationSerializer(serializers.ModelSerializer):
    """
            规格表序列化器
            "spu": "SPU商品名称",
            "spu_id": "SPU商品id",
            "options": [
                {
                    "id": "选项id",
                    "value": "选项名称"
                },
                ...
            ]
    """
    # 副表嵌套主表   SPUSpecification副表 spu表是主表
    spu = serializers.StringRelatedField(read_only=True)
    spu_id = serializers.IntegerField()
    # 主表嵌套副表返回  SPUSpecification主表  SpecificationOption是副表
    options = SpecificationOptionSerialzier(many=True)

    class Meta:
        model = SPUSpecification
        fields = '__all__'
